/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** *****************************************************************************************************
 * \file     Ea.c                                                                                       *
 * \brief    AUTOSAR 4.3.1 MCAL EEPROM Abstraction                                                      *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2024/11/13     <td>1.0.0                               *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "cdefs.h"
#include "Mcal.h"
#include "debug.h"

#include "Ea.h"
#include "Ea_Ops.h"
#include "Ea_Cfg.h"
#include "Ea_Fault.h"

#if (EA_DEV_ERROR_DETECT == STD_ON)
#include "Det.h"
#endif /* EA_DEV_ERROR_DETECT == STD_ON */

/********************************************************************************************************
 *                                 Global Macro definition                                              *
 *******************************************************************************************************/
/* Job end notification routine provided by the upper layer module (declaration) */
EA_NVM_JOB_END_NOTIFICATION_DECL

/* Job error notification routine provided by the upper layer module (declaration) */
EA_NVM_JOB_ERROR_NOTIFICATION_DECL

/********************************************************************************************************
 *                                  Private Constant Definitions                                        *
 *******************************************************************************************************/
#define EA_START_SEC_VAR_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

Ea_StateType Ea_State = {
    MEMIF_UNINIT,           /* Ea_eModuleStatus */
    MEMIF_JOB_OK,           /* Ea_eJobResult */
    EA_JOB_DONE,            /* Ea_eJob */
    EA_JOB_DONE,            /* Ea_eEepJob */
    0,                      /* Ea_uJobBlockIndex */
    0,                      /* Ea_uJobBlockNumber */
    0,                      /* Ea_uJobBlockOffset */
    0,                      /* Ea_uJobBlockLength */
    NULL_PTR,               /* Ea_pJobReadDataDestPtr */
    NULL_PTR,               /* Ea_pJobWriteDataDestPtr */
    EA_INTERNAL_UNINIT,     /* Ea_eInternalStatus */
    EA_INTERNAL_JOB_OK,     /* Ea_eInternalJobResult */
    EA_INTERNAL_JOB_DONE,   /* Ea_eInternalJob */
    EA_INTERNAL_JOB_DONE,   /* Ea_eInternalEepJob */
    0,                      /* Ea_uJobIntDevIt */
    0,                      /* Ea_uJobIntDevOffset */
    0,                      /* Ea_uJobIntDevSize */
    0,                      /* Ea_uJobIntRecordIndex */
    0,                      /* Ea_uBackupBlockIndex */
    0,                      /* Ea_uJobDataOffset */
    0,                      /* Ea_uJobDataSize */
    0                       /* Ea_uJobMoveDataOffset */
};

#define EA_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

extern const Ea_JobFunctionVoidPtr Ea_Module_Func[EA_JOB_MAX];
extern const Ea_InternalJobFunctionVoidPtr Ea_InterFunc[EA_INTERNAL_JOB_MAX];

/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
#define EA_START_SEC_CODE
#include "Ea_MemMap.h"

static inline void Ea_DetReport(uint8 ApiId, uint8 ErrorId)
{
#if (EA_DEV_ERROR_DETECT == STD_ON)
    Det_ReportError((uint16)EA_MODULE_ID, EA_INSTANCE_ID, (ApiId), (ErrorId));
#endif /* EA_DEV_ERROR_DETECT == STD_ON */
}

static inline void Ea_DetReportRuntime(uint8 ApiId, uint8 ErrorId)
{
#if (EA_DEV_ERROR_DETECT == STD_ON)
    Det_ReportRuntimeError((uint16)EA_MODULE_ID, EA_INSTANCE_ID, (ApiId),
                           (ErrorId));
#endif /* EA_DEV_ERROR_DETECT == STD_ON */
}

#define EA_STOP_SEC_CODE
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE_FAST
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief  Schedule subsequent jobs.
 *
 * \verbatim
 * Syntax             : MemIf_JobResultType Ea_JobSchedule( void )
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : JOB execution result
 *
 * Description        : The corresponding JOB is executed based on the Ea status.
 *
 * \endverbatim
 *******************************************************************************************************/
static MemIf_JobResultType Ea_JobSchedule( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;

    EA_DEBUG("Ea_eJob %d config Ea_Module_Func\n", pEa_State->Ea_eJob);

    if (Eep_GetStatus() != MEMIF_IDLE) {
        eRetVal = MEMIF_JOB_PENDING;
        return ( eRetVal );
    }

    if (Ea_Module_Func[pEa_State->Ea_eJob]) {

        eRetVal = Ea_Module_Func[pEa_State->Ea_eJob]();

    }
    else {

        EA_ERROR("Ea_eJob %d not config Ea_Module_Func\n", pEa_State->Ea_eJob);
        eRetVal = MEMIF_JOB_FAILED;

    }

    return ( eRetVal );
}

/** *****************************************************************************************************
 * \brief  Schedule subsequent jobs.
 *
 * \verbatim
 * Syntax             : MemIf_JobResultType Ea_Internal_JobSchedule( void )
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : JOB execution result
 *
 * Description        : The corresponding JOB is executed based on the Ea status.
 *
 * \endverbatim
 *******************************************************************************************************/
static Ea_Internal_JobResultType Ea_Internal_JobSchedule( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;

    EA_DEBUG("Ea_eInternalJob %d config Ea_InterFunc\n",
             pEa_State->Ea_eInternalJob);

    if (Eep_GetStatus() != MEMIF_IDLE) {
        eRetVal = EA_INTERNAL_JOB_PENDING;
        return ( eRetVal );
    }

    if (Ea_InterFunc[pEa_State->Ea_eInternalJob]) {

        eRetVal = Ea_InterFunc[pEa_State->Ea_eInternalJob]();

    }
    else {

        EA_ERROR("Ea_eInternalJob %d not config Ea_InterFunc\n",
                 pEa_State->Ea_eInternalJob);
        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return ( eRetVal );
}

#define EA_STOP_SEC_CODE_FAST
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief This function ea init.
 *
 * \verbatim
 * Syntax             : void Ea_Init(const Ea_ConfigType *ConfigPtr )
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Asynchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : ConfigPtr - Pointer to block configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Initializes the EA
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_Init(const Ea_ConfigType *ConfigPtr )
{
    Ea_StateType *pEa_State = &Ea_State;

    if (NULL_PTR != ConfigPtr) {
        Ea_DetReport( EA_INIT_ID, EA_E_PARAM_POINTER);
    }
    else if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReportRuntime( EA_INIT_ID, EA_E_BUSY );
    }
    else if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ||
              EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus ) {
        Ea_DetReport( EA_INIT_ID, EA_E_INTERNAL_BUSY);
    }
    else {
        /* Schedule init job */
        pEa_State->Ea_eJob = EA_JOB_DONE;
        pEa_State->Ea_eModuleStatus = MEMIF_BUSY_INTERNAL;
        pEa_State->Ea_eJobResult = MEMIF_JOB_OK;

        /* set Internal job */
        pEa_State->Ea_eInternalStatus = EA_INTERNAL_INIT;
        pEa_State->Ea_eInternalJobResult = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT;
    }
}

#if (EA_SETMODE_API_SUPPORTED == STD_ON)
/** *****************************************************************************************************
 * \brief This function set ea mode.
 *
 * \verbatim
 * Syntax             : void Ea_SetMode( MemIf_ModeType Mode )
 *
 * Service ID[hex]    : 0x01
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : Mode - Pointer to mode
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Call the Eep_SetMode function
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_SetMode( MemIf_ModeType Mode )
{
    Ea_StateType *pEa_State = &Ea_State;

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_SET_MODE_ID, EA_E_UNINIT );
    }
    else if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReportRuntime( EA_SET_MODE_ID, EA_E_BUSY );
    }
    else if ( EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus ) {
        Ea_DetReport( EA_SET_MODE_ID, EA_E_INTERNAL_BUSY);
    }
    else if ( EA_INTERNAL_BUSY == pEa_State->Ea_eInternalStatus ) {
        Ea_DetReport( EA_SET_MODE_ID, EA_E_INTERNAL_BUSY);
    }
    else {
        Eep_SetMode( Mode );
    }
}
#endif

/** *****************************************************************************************************
 * \brief This function ea read.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Ea_Read( uint16 BlockNumber,
 *                                               uint16 BlockOffset,
 *                                               uint8 *DataBufferPtr,
 *                                               uint16 Length )
 *
 * Service ID[hex]    : 0x02
 *
 * Sync/Async         : Asynchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : BlockNumber - block number
 *                      BlockOffset - block addr offset
 *                      DataBufferPtr - Pointer to data buffer
 *                      Length - Number of bytes to read
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Std_ReturnType ( E_OK / E_NOT_OK )
 *
 * Description        : Reads from ea block
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Ea_Read( uint16 BlockNumber,
                        uint16 BlockOffset,
                        uint8 *DataBufferPtr,
                        uint16 Length )
{
    Std_ReturnType uRetVal = (Std_ReturnType)E_OK;
    Ea_StateType *pEa_State = &Ea_State;
    uint16 uBlockIndex = Ea_GetBlockIndex(BlockNumber);

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_READ_ID, EA_E_UNINIT );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReportRuntime( EA_READ_ID, EA_E_BUSY );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( EA_BLOCK_INDEX_DEF == uBlockIndex ) {
        Ea_DetReport( EA_READ_ID, EA_E_INVALID_BLOCK_NO);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( BlockOffset >= Ea_BlockConfig[uBlockIndex].blockSize ) {
        Ea_DetReport( EA_READ_ID, EA_E_INVALID_BLOCK_OFS);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ((0U == Length)
             || ((BlockOffset + Length) > Ea_BlockConfig[uBlockIndex].blockSize)) {
        Ea_DetReport( EA_READ_ID, EA_E_INVALID_BLOCK_LEN);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( NULL_PTR == DataBufferPtr ) {
        Ea_DetReport( EA_READ_ID, EA_E_PARAM_POINTER);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else {

        /* Configure the read job */
        pEa_State->Ea_uJobBlockIndex = uBlockIndex;

        pEa_State->Ea_uJobBlockNumber = BlockNumber;
        pEa_State->Ea_uJobBlockOffset = BlockOffset;
        pEa_State->Ea_uJobBlockLength = Length;
        pEa_State->Ea_pJobReadDataDestPtr = DataBufferPtr;

        pEa_State->Ea_eJob = EA_JOB_READ;

        pEa_State->Ea_eModuleStatus = MEMIF_BUSY;

        /* Execute the read job */
        pEa_State->Ea_eJobResult = MEMIF_JOB_PENDING;
    }

    return ( uRetVal );
}

/** *****************************************************************************************************
 * \brief This function write block.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Ea_Write( uint16 BlockNumber,
 *                                                const uint8 *DataBufferPtr )
 *
 * Service ID[hex]    : 0x03
 *
 * Sync/Async         : Asynchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : BlockNumber - block number
 *                      DataBufferPtr - Pointer to data buffer
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Std_ReturnType ( E_OK / E_NOT_OK )
 *
 * Description        : Writes to ea block
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Ea_Write( uint16 BlockNumber,
                         const uint8 *DataBufferPtr )
{
    Std_ReturnType uRetVal = (Std_ReturnType)E_OK;
    Ea_StateType *pEa_State = &Ea_State;
    uint16 uBlockIndex = Ea_GetBlockIndex(BlockNumber);

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_WRITE_ID, EA_E_UNINIT );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReportRuntime( EA_WRITE_ID, EA_E_BUSY );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( EA_BLOCK_INDEX_DEF == uBlockIndex ) {
        Ea_DetReport( EA_WRITE_ID, EA_E_INVALID_BLOCK_NO);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( NULL_PTR == DataBufferPtr ) {
        Ea_DetReport( EA_WRITE_ID, EA_E_PARAM_POINTER);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else {

        /* Configure the write job */
        pEa_State->Ea_uJobBlockIndex = uBlockIndex;
        pEa_State->Ea_uJobBlockNumber = BlockNumber;
        pEa_State->Ea_pJobWriteDataDestPtr = DataBufferPtr;

        pEa_State->Ea_eJob = EA_JOB_WRITE;

        pEa_State->Ea_eModuleStatus = MEMIF_BUSY;

        /* Execute the write job */
        pEa_State->Ea_eJobResult = MEMIF_JOB_PENDING;
    }

    return ( uRetVal );
}

/** *****************************************************************************************************
 * \brief This function ea Cancel.
 *
 * \verbatim
 * Syntax             : void Ea_Cancel( void )
 *
 * Service ID[hex]    : 0x04
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Cancels an ongoing job
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_Cancel( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_CANCEL_ID, EA_E_UNINIT );
    }
    else {
        if ( MEMIF_JOB_PENDING == pEa_State->Ea_eJobResult ) {
            /* Cancel ongoing Eep job if any */
            if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
                pEa_State->Ea_eJobResult = MEMIF_JOB_CANCELED;
                pEa_State->Ea_eJob = EA_JOB_DONE;
                Eep_Cancel();
                pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
            }
            else {
                Ea_DetReportRuntime( EA_CANCEL_ID, EA_E_INVALID_CANCEL );
            }
        }
    }
}

/** *****************************************************************************************************
 * \brief This function returns the ea state.
 *
 * \verbatim
 * Syntax             : MemIf_StatusType Ea_GetStatus( void )
 *
 * Service ID[hex]    : 0x05
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : MemIf_StatusType
 *
 * Description        : Returns the ea state
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
MemIf_StatusType Ea_GetStatus( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    return ( pEa_State->Ea_eModuleStatus );
}

#define EA_STOP_SEC_CODE
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE_FAST
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief This function returns the result of the last job.
 *
 * \verbatim
 * Syntax             : MemIf_JobResultType Ea_GetJobResult( void )
 *
 * Service ID[hex]    : 0x06
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : MemIf_JobResultType
 *
 * Description        : Returns the result of the last job
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
MemIf_JobResultType Ea_GetJobResult( void )
{
    Ea_StateType *pEa_State = &Ea_State;
    MemIf_JobResultType eRetVal = pEa_State->Ea_eJobResult;

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_GETJOBRESULT_ID, EA_E_UNINIT );
        eRetVal = MEMIF_JOB_FAILED;
    }

    return ( eRetVal );
}

#define EA_STOP_SEC_CODE_FAST
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief This function returns the ea job.
 *
 * \verbatim
 * Syntax             : Ea_JobType Ea_GetJob( void )
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Ea_JobType
 *
 * Description        : Returns the ea state
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Ea_JobType Ea_GetJobType( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    return ( pEa_State->Ea_eJob );
}

/** *****************************************************************************************************
 * \brief This function returns the ea internal state.
 *
 * \verbatim
 * Syntax             : Ea_Internal_StatusType EaIntl_GetStatus( void )
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Ea_Internal_StatusType
 *
 * Description        : Returns the ea internal state
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Ea_Internal_StatusType EaIntl_GetStatus( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    return ( pEa_State->Ea_eInternalStatus );
}

/** *****************************************************************************************************
 * \brief This function returns the result of the last internal job.
 *
 * \verbatim
 * Syntax             : Ea_Internal_JobResultType EaIntl_GetJobResult( void )
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Ea_Internal_JobResultType
 *
 * Description        : Returns the result of the last internal job
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Ea_Internal_JobResultType EaIntl_GetJobResult( void )
{
    Ea_StateType *pEa_State = &Ea_State;
    Ea_Internal_JobResultType eRetVal = pEa_State->Ea_eInternalJobResult;

    if ( EA_INTERNAL_UNINIT == pEa_State->Ea_eInternalStatus ) {
        eRetVal = EA_INTERNAL_JOB_FAILED;
    }

    return ( eRetVal );
}

/** *****************************************************************************************************
 * \brief This function returns the ea internal job.
 *
 * \verbatim
 * Syntax             : Ea_Internal_JobType EaIntl_GetJobType( void )
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Ea_Internal_JobType
 *
 * Description        : Returns the ea internal job
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Ea_Internal_JobType EaIntl_GetJobType( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    return ( pEa_State->Ea_eInternalJob );
}

/** *****************************************************************************************************
 * \brief This function set ea block invalid.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Ea_InvalidateBlock( uint16 uBlockNumber )
 *
 * Service ID[hex]    : 0x07
 *
 * Sync/Async         : Asynchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : uBlockNumber - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Std_ReturnType ( E_OK / E_NOT_OK )
 *
 * Description        : set ea block invalid
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Ea_InvalidateBlock( uint16 BlockNumber )
{
    Std_ReturnType uRetVal = (Std_ReturnType)E_OK;
    Ea_StateType *pEa_State = &Ea_State;
    uint16 uBlockIndex = Ea_GetBlockIndex(BlockNumber);

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_INVALIDATEBLOCK_ID, EA_E_UNINIT );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReportRuntime( EA_INVALIDATEBLOCK_ID, EA_E_BUSY );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( EA_BLOCK_INDEX_DEF == uBlockIndex ) {
        Ea_DetReport( EA_INVALIDATEBLOCK_ID, EA_E_INVALID_BLOCK_NO);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else {

        /* Configure the invalidate block job */
        pEa_State->Ea_uJobBlockIndex = uBlockIndex;
        pEa_State->Ea_uJobBlockNumber = BlockNumber;

        pEa_State->Ea_eJob = EA_JOB_INVAL_BLOCK;

        pEa_State->Ea_eModuleStatus = MEMIF_BUSY;

        /* Execute the invalidate block job */
        pEa_State->Ea_eJobResult = MEMIF_JOB_PENDING;

        uRetVal = (Std_ReturnType)E_OK;
    }

    return ( uRetVal );
}

#if (EA_VERSION_INFO_API == STD_ON)

/** *****************************************************************************************************
 * \brief This function get ea VersionInfo.
 *
 * \verbatim
 * Syntax             : void Ea_GetVersionInfo( Std_VersionInfoType *pVersionInfoPtr )
 *
 * Service ID[hex]    : 0x08
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : pVersionInfoPtr - Pointer to VersionInfo
 *
 * Return value       : None
 *
 * Description        : get ea VersionInfo
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_GetVersionInfo( Std_VersionInfoType *VersionInfoPtr )
{
    /* Development Error Checks */
    if ( NULL_PTR == VersionInfoPtr ) {
        Ea_DetReport( EA_GETVERSIONINFO_ID, EA_E_PARAM_POINTER );
    }
    else {

        VersionInfoPtr->moduleID = (uint16)EA_MODULE_ID;
        VersionInfoPtr->vendorID = (uint16)EA_VENDOR_ID;
        VersionInfoPtr->sw_major_version = (uint8)EA_SW_MAJOR_VERSION;
        VersionInfoPtr->sw_minor_version = (uint8)EA_SW_MINOR_VERSION;
        VersionInfoPtr->sw_patch_version = (uint8)EA_SW_PATCH_VERSION;
    }
}

#endif /* EA_VERSION_INFO_API == STD_ON */

/** *****************************************************************************************************
 * \brief This function erase immediate block.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Ea_EraseImmediateBlock( uint16 BlockNumber )
 *
 * Service ID[hex]    : 0x09
 *
 * Sync/Async         : Asynchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : BlockNumber - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Std_ReturnType ( E_OK / E_NOT_OK )
 *
 * Description        : ea erase immediate block
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Ea_EraseImmediateBlock( uint16 BlockNumber )
{
    Std_ReturnType uRetVal = (Std_ReturnType)E_OK;
    Ea_StateType *pEa_State = &Ea_State;
    uint16 uBlockIndex = Ea_GetBlockIndex(BlockNumber);

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_ERASEIMMEDIATE_BLOCK_ID, EA_E_UNINIT );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( MEMIF_BUSY == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReportRuntime( EA_ERASEIMMEDIATE_BLOCK_ID, EA_E_BUSY );
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( EA_BLOCK_INDEX_DEF == uBlockIndex ) {
        Ea_DetReport( EA_ERASEIMMEDIATE_BLOCK_ID, EA_E_INVALID_BLOCK_NO);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else if ( (boolean)FALSE == Ea_BlockConfig[uBlockIndex].immediateData ) {
        Ea_DetReport( EA_ERASEIMMEDIATE_BLOCK_ID, EA_E_INVALID_BLOCK_NO);
        uRetVal = (Std_ReturnType)E_NOT_OK;
    }
    else {

        /* Configure the write job */
        pEa_State->Ea_uJobBlockIndex = uBlockIndex;
        pEa_State->Ea_uJobBlockNumber = BlockNumber;

        pEa_State->Ea_eJob = EA_JOB_ERASE_IMMEDIATE;

        pEa_State->Ea_eModuleStatus = MEMIF_BUSY;

        /* Execute the write job */
        pEa_State->Ea_eJobResult = MEMIF_JOB_PENDING;
    }

    return ( uRetVal );
}

#define EA_STOP_SEC_CODE
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE_FAST
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief This function report the EA module the successful end of an asynchronous operation.
 *
 * \verbatim
 * Syntax             : void Ea_JobEndNotification( void )
 *
 * Service ID[hex]    : 0x10
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : report the EA module the successful end of an asynchronous operation
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_JobEndNotification( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    /* Fault error interface */
    Ea_JobEndNotification_Exception();

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_JOBENDNOTIFICATION_ID, EA_E_UNINIT );
    }

#if (EA_POLLING_MODE == STD_OFF)

    else {
        /* Check the internal status of Ea */
        if (EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus &&
                EA_INTERNAL_JOB_PENDING == pEa_State->Ea_eInternalJobResult) {

            /* EA internal task execution completed */
            if ( EA_INTERNAL_JOB_DONE == pEa_State->Ea_eInternalJob ) {

                /* EA internal status configuration */
                pEa_State->Ea_eInternalJobResult = EA_INTERNAL_JOB_OK;
                pEa_State->Ea_eInternalStatus = EA_INTERNAL_IDLE;

                /* EA module status configuration */
                if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
                }
            }
            else {
                /* Continue to perform EA internal tasks */
                pEa_State->Ea_eInternalJobResult = Ea_Internal_JobSchedule();

                if ( EA_INTERNAL_JOB_PENDING == pEa_State->Ea_eInternalJobResult ) {
                    /* Nothing to do */
                }
                else if ( EA_INTERNAL_JOB_OK == pEa_State->Ea_eInternalJobResult ) {

                    /* EA internal status configuration */
                    pEa_State->Ea_eInternalStatus = EA_INTERNAL_IDLE;

                    /* EA module status configuration */
                    if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                        pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
                    }
                }
                else {
                    /* Initialization process, configuration initialization failed */
                    if ( EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus ) {
                        /* EA internal status configuration */
                        pEa_State->Ea_eInternalStatus = EA_INTERNAL_UNINIT;

                        /* EA module status configuration */
                        pEa_State->Ea_eJobResult = Eep_GetJobResult();

                        /* Fault error interface */
                        Ea_Eep_GetJobResult_Exception();

                        pEa_State->Ea_eModuleStatus = MEMIF_UNINIT;

                    }
                    else {
                        /* EA internal status configuration */
                        pEa_State->Ea_eInternalStatus = EA_INTERNAL_IDLE;
                    }
                }
            }
        }
        /* Check the module status of Ea */
        else if ( MEMIF_JOB_PENDING == pEa_State->Ea_eJobResult) {
            if ( EA_JOB_DONE == pEa_State->Ea_eJob ) {
                /* Last schedule Eep job finished */
                pEa_State->Ea_eJobResult = Eep_GetJobResult();

                /* Fault error interface */
                Ea_Eep_GetJobResult_Exception();

                if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                    /* no notifications from internal jobs */
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
                }
                else {
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;

                    /* Call job end notification function */
                    EA_NVM_JOB_END_NOTIFICATION
                }
            }
            else {
                pEa_State->Ea_eJobResult = Ea_JobSchedule();

                if ( MEMIF_JOB_OK == pEa_State->Ea_eJobResult ) {
                    if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                        /* no notifications from internal jobs */
                        pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
                    }
                    else {
                        pEa_State->Ea_eModuleStatus = MEMIF_IDLE;

                        /* Call job end notification function */
                        EA_NVM_JOB_END_NOTIFICATION
                    }
                }
                else if ( MEMIF_JOB_PENDING == pEa_State->Ea_eJobResult ) {
                    /* Nothing to do (ongoing Eep job) */
                }
                else {

                    if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                        /* no notifications from internal jobs */
                        pEa_State->Ea_eModuleStatus = MEMIF_UNINIT;
                    }
                    else {
                        pEa_State->Ea_eModuleStatus = MEMIF_IDLE;

                        /* Call job error notification function */
                        EA_NVM_JOB_ERROR_NOTIFICATION
                    }
                }
            }
        }
    }

#endif  /* EA_POLLING_MODE == STD_ON */

}

#define EA_STOP_SEC_CODE_FAST
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief This function report the EA module the failure end of an asynchronous operation.
 *
 * \verbatim
 * Syntax             : void Ea_JobErrorNotification( void )
 *
 * Service ID[hex]    : 0x11
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : report the EA module the failure end of an asynchronous operation
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_JobErrorNotification( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_JOBERRORNOTIFICATION_ID, EA_E_UNINIT );
    }

#if (EA_POLLING_MODE == STD_OFF)

    else {

        if (EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus ||
                EA_INTERNAL_BUSY == pEa_State->Ea_eInternalStatus) {

            if ( EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus ) {
                /* EA internal status configuration */
                pEa_State->Ea_eInternalJobResult = EA_INTERNAL_JOB_FAILED;
                pEa_State->Ea_eInternalStatus = EA_INTERNAL_UNINIT;

                /* EA module status configuration */
                pEa_State->Ea_eJobResult = Eep_GetJobResult();
                pEa_State->Ea_eModuleStatus = MEMIF_UNINIT;

                /* Fault error interface */
                Ea_Eep_GetJobResult_Exception();

            }
            else {
                pEa_State->Ea_eInternalJobResult = EA_INTERNAL_JOB_FAILED;
                pEa_State->Ea_eInternalStatus = EA_INTERNAL_IDLE;
            }
        }
        else {

            if ( MEMIF_JOB_CANCELED == pEa_State->Ea_eJobResult ) {
                /* Eep job has been canceled. Do nothing in this callback.
                    The NvM_JobErrorNotification() callback will be called from
                    the Ea_Cancel()function which called the Eep_Cancel() function */
            }
            else {
                pEa_State->Ea_eJobResult = Eep_GetJobResult();

                /* Fault error interface */
                Ea_Eep_GetJobResult_Exception();

                switch (pEa_State->Ea_eEepJob) {
                    case EA_JOB_WRITE_BACKUP_RECORD_INFO:
                    case EA_JOB_WRITE_READ_BACKUP_RECORD_DATA:
                    case EA_JOB_WRITE_SYNC_BACKUP_RECORD_DATA:
                    case EA_JOB_WRITE_BACKUP_RECORD_ACTIVE:
                    case EA_JOB_WRITE_MOVE_BACKUP_RECORD_INFO:
                    case EA_JOB_WRITE_MOVE_READ_BACKUP_RECORD_DATA:
                    case EA_JOB_WRITE_MOVE_SYNC_BACKUP_RECORD_DATA:
                    case EA_JOB_WRITE_MOVE_BACKUP_RECORD_ACTIVE:
                    case EA_JOB_WRITE_BLOCK_INFO_END:
                    case EA_JOB_WRITE_RECORD_INFO:
                    case EA_JOB_WRITE_BLOCK_DATA_END:
                    case EA_JOB_WRITE_RECORD_DATA:
                    case EA_JOB_WRITE_RECORD_ACTIVE:
                    case EA_JOB_INVAL_BLOCK_INFO:
                        Ea_JobWrite_SyncBlockInfo();
                        pEa_State->Ea_eEepJob = EA_JOB_DONE;
                        break;

                    default:
                        break;
                }

                if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                    /* No notifications from internal jobs */
                    pEa_State->Ea_eModuleStatus = MEMIF_UNINIT;
                }
                else {
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;

                    /* Call job error notification function */
                    EA_NVM_JOB_ERROR_NOTIFICATION
                }
            }
        }
    }

#endif  /* EA_POLLING_MODE == STD_ON */

}

#define EA_STOP_SEC_CODE
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE_FAST
#include "Ea_MemMap.h"

/** *****************************************************************************************************
 * \brief This function performs the processing of jobs.
 *
 * \verbatim
 * Syntax             : void Ea_MainFunction( void )
 *
 * Service ID[hex]    : 0x12
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Performs the processing of jobs
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
void Ea_MainFunction( void )
{
    Ea_StateType *pEa_State = &Ea_State;

    if ( MEMIF_UNINIT == pEa_State->Ea_eModuleStatus ) {
        Ea_DetReport( EA_MAINFUNCTION_ID, EA_E_UNINIT );
    }
    else {
        if (EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus &&
                EA_INTERNAL_JOB_PENDING == pEa_State->Ea_eInternalJobResult) {
            switch ( pEa_State->Ea_eInternalJob ) {
                case EA_INTERNAL_JOB_INT:
                    pEa_State->Ea_eInternalJobResult = Ea_Internal_JobSchedule();
                    break;

#if (EA_POLLING_MODE == STD_ON)

                case EA_INTERNAL_JOB_INT_GET_DEV_INFO:
                case EA_INTERNAL_JOB_INT_PARES_DEV_INFO:
                case EA_INTERNAL_JOB_INT_SET_DEV_INFO:
                case EA_INTERNAL_JOB_INT_SET_BLOCK_DATA_END:
                case EA_INTERNAL_JOB_INT_SET_BLOCK_INFO_END:
                case EA_INTERNAL_JOB_INT_GET_BLOCK_INFO:
                case EA_INTERNAL_JOB_INT_PARES_BLOCK_INFO:
                case EA_INTERNAL_JOB_INT_BLOCK_INFO_LOOP:
                case EA_INTERNAL_JOB_INT_GET_BLOCK_DATA_END:
                case EA_INTERNAL_JOB_INT_PARES_BLOCK_DATA_END:
                case EA_INTERNAL_JOB_INT_GET_BACKUP_BLOCK_INFO:
                case EA_INTERNAL_JOB_INT_PARES_BACKUP_BLOCK_INFO:
                case EA_INTERNAL_JOB_INT_READ_BACKUP_BLOCK_DATA:
                case EA_INTERNAL_JOB_INT_SYNC_BACKUP_BLOCK_DATA:
                case EA_INTERNAL_JOB_INT_BACKUP_BLOCK_ACTIVE:
                case EA_INTERNAL_JOB_INT_DONE:

                case EA_INTERNAL_JOB_DONE:

                    pEa_State->Ea_eInternalJobResult = Ea_Internal_JobSchedule();
                    break;

#endif    /* EA_POLLING_MODE == STD_ON */

                default:
                    /* Internal or subsequent job */
                    break;
            }

            if ( EA_INTERNAL_JOB_PENDING == pEa_State->Ea_eInternalJobResult ) {
                /* Nothing to do */
            }
            else if ( EA_INTERNAL_JOB_OK == pEa_State->Ea_eInternalJobResult ) {
                pEa_State->Ea_eInternalStatus = EA_INTERNAL_IDLE;

                if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
                }
            }
            else {
                if ( EA_INTERNAL_INIT == pEa_State->Ea_eInternalStatus ) {
                    pEa_State->Ea_eInternalStatus = EA_INTERNAL_UNINIT;
                    pEa_State->Ea_eModuleStatus = MEMIF_UNINIT;
                    pEa_State->Ea_eJobResult = Eep_GetJobResult();
                }
                else {
                    pEa_State->Ea_eInternalStatus = EA_INTERNAL_IDLE;
                }
            }
        }
        else if ( MEMIF_JOB_PENDING == pEa_State->Ea_eJobResult) {
            switch ( pEa_State->Ea_eJob ) {
                /* for all the following jobs subsequent jobs will be called in Ea job schedule
                   function based on Job */
                case EA_JOB_READ:
                case EA_JOB_WRITE:
                case EA_JOB_INVAL_BLOCK:
                case EA_JOB_ERASE_IMMEDIATE:
                    pEa_State->Ea_eJobResult = Ea_JobSchedule();
                    break;

#if (EA_POLLING_MODE == STD_ON)

                case EA_JOB_READ_DATA:

                case EA_JOB_WRITE_BACKUP_RECORD_INFO:
                case EA_JOB_WRITE_READ_BACKUP_RECORD_DATA:
                case EA_JOB_WRITE_SYNC_BACKUP_RECORD_DATA:
                case EA_JOB_WRITE_BACKUP_RECORD_ACTIVE:

                case EA_JOB_WRITE_MOVE_BACKUP_RECORD_INFO:
                case EA_JOB_WRITE_MOVE_READ_BACKUP_RECORD_DATA:
                case EA_JOB_WRITE_MOVE_SYNC_BACKUP_RECORD_DATA:
                case EA_JOB_WRITE_MOVE_BACKUP_RECORD_ACTIVE:

                case EA_JOB_WRITE_BLOCK_INFO_END:
                case EA_JOB_WRITE_RECORD_INFO:
                case EA_JOB_WRITE_BLOCK_DATA_END:
                case EA_JOB_WRITE_RECORD_DATA:
                case EA_JOB_WRITE_RECORD_ACTIVE:

                case EA_JOB_INVAL_BLOCK_INFO:

                case EA_JOB_DONE:
                    pEa_State->Ea_eJobResult = Ea_JobSchedule();
                    break;

#endif    /* EA_POLLING_MODE == STD_ON */

                default:
                    /* Internal or subsequent job */
                    break;
            }

            if ( MEMIF_JOB_PENDING == pEa_State->Ea_eJobResult ) {
                /* Nothing to do */
            }
            else if ( MEMIF_JOB_OK == pEa_State->Ea_eJobResult ) {
                if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                    /* no notifications from internal jobs */
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;
                }
                else {
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;

                    /* Call job end notification function */
                    EA_NVM_JOB_END_NOTIFICATION
                }
            }
            else {
                if ( MEMIF_BUSY_INTERNAL == pEa_State->Ea_eModuleStatus ) {
                    /* no notifications from internal jobs */
                    pEa_State->Ea_eModuleStatus = MEMIF_UNINIT;
                }
                else {
                    pEa_State->Ea_eModuleStatus = MEMIF_IDLE;

                    /* Call job error notification function */
                    EA_NVM_JOB_ERROR_NOTIFICATION
                }
            }
        }
    }
}

#define EA_STOP_SEC_CODE_FAST
#include "Ea_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @}*/
/* End of file */
